package com.vshop.platform.system.crud.dao;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.mybatisflex.core.query.QueryMethods;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.vshop.framework.core.constant.Const;
import com.vshop.framework.core.exception.ServiceException;
import com.vshop.framework.satoken.helper.LoginHelper;
import com.vshop.platform.system.domain.entity.SysRole;
import com.vshop.platform.system.crud.mapper.SysRoleMapper;
import com.vshop.platform.system.domain.param.SysRoleParam;
import com.vshop.platform.system.domain.vo.SysRoleVo;
import org.springframework.stereotype.Repository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.util.*;

import static com.vshop.platform.system.domain.entity.table.SysDeptTableDef.SysDeptTable;
import static com.vshop.platform.system.domain.entity.table.SysRoleTableDef.SysRoleTable;
import static com.vshop.platform.system.domain.entity.table.SysUserRoleTableDef.SysUserRoleTable;
import static com.vshop.platform.system.domain.entity.table.SysUserTableDef.SysUserTable;


/**
 * 角色信息表 服务层实现。
 *
 * @author vshop
 * @since 2024-11-18
 */
@RequiredArgsConstructor
@Slf4j
@Repository
public class SysRoleDao extends ServiceImpl<SysRoleMapper, SysRole> {
    public QueryWrapper buildQueryWrapper(SysRoleParam param) {
        Map<String, Object> params = param.getParams();
        return QueryWrapper.create()
                .from(SysRoleTable)
                .and(SysRoleTable.RoleId.eq(param.getRoleId()))
                .and(SysRoleTable.RoleName.like(param.getRoleName()))
                .and(SysRoleTable.Status.eq(param.getStatus()))
                .and(SysRoleTable.RoleKey.like(param.getRoleKey()))
                .and(SysRoleTable.CreateTime.between(params.get("beginTime"), params.get("endTime")))
                .orderBy(SysRoleTable.SortNum.asc())
                .orderBy(SysRoleTable.CreateTime.asc());
    }

    public QueryWrapper buildQueryWrapperOptionSelect() {
        return QueryWrapper.create()
                .from(SysRoleTable)
                .where(SysRoleTable.Status.eq(Const.StatusNormal))
                .orderBy(SysRoleTable.SortNum.asc())
                .orderBy(SysRoleTable.CreateTime.asc());
    }

    /**
     * 根据用户ID查询角色列表
     */
    public List<SysRole> listUserRoleByUserId(Long userId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .from(SysRoleTable)
                .leftJoin(SysUserRoleTable).on(SysUserRoleTable.RoleId.eq(SysRoleTable.RoleId))
                .where(SysUserRoleTable.UserId.eq(userId));
        return this.listAs(queryWrapper, SysRole.class);
    }

    /**
     * 根据用户ID查询权限
     *
     * @param userId 用户ID
     * @return 权限列表
     */
    public Set<String> listRolePermissionByUserId(Long userId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(QueryMethods.distinct(SysRoleTable.AllColumns))
                .from(SysRoleTable.as("r"))
                .leftJoin(SysUserRoleTable).as("ur").on(SysUserRoleTable.RoleId.eq(SysRoleTable.RoleId))
                .leftJoin(SysUserTable).as("u").on(SysUserTable.UserId.eq(SysUserRoleTable.UserId))
                .leftJoin(SysDeptTable).as("d").on(SysDeptTable.DeptId.eq(SysUserTable.DeptId))
                .where(SysUserRoleTable.UserId.eq(userId));
        List<SysRoleVo> perms = this.listAs(queryWrapper, SysRoleVo.class);
        //List<SysRole> perms = roleMapper.selectRolePermissionByUserId(userId);
        Set<String> permsSet = new HashSet<>();
        for (SysRoleVo perm : perms) {
            if (ObjectUtil.isNotNull(perm)) {
                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
            }
        }
        return permsSet;
    }


    /**
     * 校验角色名称是否唯一
     */
    public boolean checkExistRoleName(SysRoleParam param) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .from(SysRoleTable)
                .where(SysRoleTable.RoleName.eq(param.getRoleName()))
                .and(SysRoleTable.RoleId.ne(param.getRoleId()));
        return this.exists(queryWrapper);
    }

    /**
     * 校验角色权限是否唯一
     */
    public boolean checkExistRoleKey(SysRoleParam param) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .from(SysRoleTable)
                .where(SysRoleTable.RoleKey.eq(param.getRoleKey()))
                .and(SysRoleTable.RoleId.ne(param.getRoleId()));
        return this.exists(queryWrapper);
    }

    /**
     * 校验角色是否允许操作
     *
     * @param param 角色信息
     */
    public void checkRoleAllowed(SysRoleParam param) {
        if (ObjectUtil.isNotNull(param.getRoleId()) && LoginHelper.isSuperAdmin(param.getRoleId())) {
            throw new ServiceException("不允许操作超级管理员角色");
        }
        String[] keys = new String[]{Const.SuperAdminRoleKey, Const.TenantAdminRoleKey};
        // 新增:不允许使用 管理员标识符
        if (ObjectUtil.isNull(param.getRoleId())
                && StrUtil.equalsAny(param.getRoleKey(), keys)) {
            throw new ServiceException("不允许使用系统内置管理员角色标识符!");
        }
        // 修改:不允许修改 管理员标识符
        if (ObjectUtil.isNotNull(param.getRoleId())) {
            SysRole sysRole = this.getById(param.getRoleId());
            // 如果标识符不相等 判断为修改了管理员标识符
            if (!StrUtil.equals(sysRole.getRoleKey(), param.getRoleKey())) {
                if (StrUtil.equalsAny(sysRole.getRoleKey(), keys)) {
                    throw new ServiceException("不允许修改系统内置管理员角色标识符!");
                } else if (StrUtil.equalsAny(param.getRoleKey(), keys)) {
                    throw new ServiceException("不允许使用系统内置管理员角色标识符!");
                }
            }
        }
    }

    /**
     * 校验角色是否存在用户
     *
     * @param roleId 角色ID
     * @return 结果
     */
    public boolean checkRoleHasUserByRoleId(Long roleId) {
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(QueryMethods.distinct(SysUserRoleTable.UserId))
                .from(SysUserRoleTable)
                .where(SysUserRoleTable.RoleId.eq(roleId));
        return this.count(queryWrapper) > 0;
    }

}
